package com.example.wan1.bus;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import io.reactivex.disposables.Disposable;


final class CacheUtils {
    //粘性map
    private final Map<Class, List<TagMessage>> stickyEventsMap = new ConcurrentHashMap<>();
    //Disposable map
    private final Map<Object, List<Disposable>> disposablesMap = new ConcurrentHashMap<>();

    private CacheUtils() {

    }

    //初始化CacheUtils
    public static CacheUtils getInstance() {
        return Holder.CACHE_UTILS;
    }


    /***
     * 添加粘性事件
     * @param event 事件
     * @param tag 标志
     */
    void addStickyEvent(final Object event, final String tag) {
        Class eventType = Utils.getClassFromObject(event);
        synchronized (stickyEventsMap) {
            List<TagMessage> stickyEvents = stickyEventsMap.get(eventType);
            if (stickyEvents == null) {
                //如果这个事件没有集合，也就是没有发送粘性事件，那么就new一个，更新数据
                stickyEvents = new ArrayList<>();
                stickyEvents.add(new TagMessage(event, tag));
                stickyEventsMap.put(eventType, stickyEvents);
            } else {
                //存在该事件发送的粘性事件,挨个判断是否存在一样的
                for (int i = stickyEvents.size() - 1; i >= 0; --i) {
                    TagMessage tmp = stickyEvents.get(i);
                    if (tmp.isSameType(eventType, tag)) {
                        Utils.logW("The sticky event already added.");
                        return;
                    }
                }
                stickyEvents.add(new TagMessage(event, tag));
            }
        }
    }

    /***
     * 移除粘性事件
     * @param event 事件
     * @param tag 标志
     */
    void removeStickyEvent(final Object event, final String tag) {
        Class eventType = Utils.getClassFromObject(event);
        synchronized (stickyEventsMap) {
            List<TagMessage> stickyEvents = stickyEventsMap.get(eventType);
            //如果没有事件，何来的移除事件，直接返回。否则遍历，如果条件全部相同，移除
            if (stickyEvents == null) return;
            for (int i = stickyEvents.size() - 1; i >= 0; --i) {
                TagMessage stickyEvent = stickyEvents.get(i);
                if (stickyEvent.isSameType(eventType, tag)) {
                    stickyEvents.remove(i);
                    break;
                }
            }
            //最后，判断下集合等于0，从map中移掉
            if (stickyEvents.size() == 0) stickyEventsMap.remove(eventType);
        }
    }

    /***
     * 发现粘性事件
     * @param eventType 事件类型
     * @param tag 标志
     * @return
     */
    TagMessage findStickyEvent(final Class eventType, final String tag) {
        synchronized (stickyEventsMap) {
            //事件集合
            List<TagMessage> stickyEvents = stickyEventsMap.get(eventType);
            if (stickyEvents == null) return null;
            //事件数量
            int size = stickyEvents.size();
            TagMessage res = null;
            //从集合中挨个查询，找到完全匹配的事件
            for (int i = size - 1; i >= 0; --i) {
                TagMessage stickyEvent = stickyEvents.get(i);
                if (stickyEvent.isSameType(eventType, tag)) {
                    res = stickyEvents.get(i);
                    break;
                }
            }
            return res;
        }
    }

    /***
     * 根据订阅者来的，增加订阅事件，添加到map中
     * @param subscriber 订阅者
     * @param disposable 订阅事件
     */
    void addDisposable(Object subscriber, Disposable disposable) {
        synchronized (disposablesMap) {
            List<Disposable> list = disposablesMap.get(subscriber);
            if (list == null) {
                list = new ArrayList<>();
                list.add(disposable);
                disposablesMap.put(subscriber, list);
            } else {
                list.add(disposable);
            }
        }
    }

    /***
     * 根据订阅者来的，移除订阅事件，清空map中所对应的那个订阅者所有数据
     * @param subscriber 订阅者
     */
    void removeDisposables(final Object subscriber) {
        synchronized (disposablesMap) {
            List<Disposable> disposables = disposablesMap.get(subscriber);
            if (disposables == null) return;
            for (Disposable disposable : disposables) {
                if (disposable != null && !disposable.isDisposed()) {
                    disposable.dispose();//订阅事件，切断连接，为了防止内存泄漏
                }
            }
            disposables.clear();
            disposablesMap.remove(subscriber);
        }
    }

    /***
     * 静态类中
     * 静态变量
     */
    private static class Holder {
        private static final CacheUtils CACHE_UTILS = new CacheUtils();
    }

}
